package com.moli.iov.down.command.design.command.retry.impl;

import com.moli.iov.down.command.codec.encode.ProtocolEncoder;
import com.moli.iov.down.command.codec.encode.data.DataEncoder;
import com.moli.iov.down.command.design.command.retry.RetryCommand;
import com.moli.iov.down.command.design.factory.DataEncoderFactory;
import com.moli.iov.down.command.mq.SendCache;
import com.moli.iov.down.command.mq.SendHandle;
import com.moli.iov.down.constants.Constant;
import com.moli.iov.down.enums.OperatorResultEnum;
import com.moli.iov.down.enums.ResResultEnum;
import com.moli.iov.down.model.dto.remoting.CommandDto;
import com.moli.iov.down.model.po.VehicleCommand;
import com.moli.iov.down.service.IVehicleCommandService;
import com.moli.iov.util.ByteArrayUtil;
import com.moli.iov.util.SpringContextUtils;
import com.moli.iov.util.StringUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * <p>
 *  普通指令处理 重试机制
 * </p>
 *
 * @author: zql
 * @Date: 2019/1/9 14:28
 */
public class GeneralCommand implements RetryCommand {
    protected final Logger logger = LoggerFactory.getLogger(this.getClass());

    private SendCache sendCache = SpringContextUtils.getBean("sendCache");

    private IVehicleCommandService vehicleCommandService =
                SpringContextUtils.getBean("vehicleCommandService");

    private SendHandle sendHandle = SpringContextUtils.getBean("sendHandle");

    @Override
    public void handle(CommandDto commandDto) {
        CommandDto commandDtoCache = sendCache.getCacheSendCommand(commandDto);
        logger.info("[补发] 缓存结果：{}, 入参：{} ", commandDtoCache, commandDto);

        String commandStr = StringUtil.bytesToHexString(commandDto.getCommand());
        String controlCommandStr = StringUtil.bytesToHexString(commandDto.getControlCommand());
        String controlContent = StringUtil.bytesToHexString(commandDto.getControlContent());


        //响应结果缓存为空，补发出超时 则取消补发
        if(commandDtoCache == null){
            logger.error("[补发] 取消 原因：[缓存commandDtoCache 为空或补发超时] vin：{}, " +
                            "command：{}, controlCommand：{}, controlContent：{}  参数：{}",
                    commandDto.getVin(), commandStr, controlCommandStr,
                    controlContent, commandDto);
            return;
        }

        String resultStr = ResResultEnum.getMsg(commandDtoCache.getResult());
        //终端已响应 或 已置为失败
        if(ResResultEnum.SUCCESS.getFlag() == commandDtoCache.getResult() ||
                ResResultEnum.ERROR.getFlag() == commandDtoCache.getResult()){

            logger.info("[补发] 取消 原因：[{}]  vin：{}, command：{}, controlCommand：{}, " +
                            "controlContent：{}  参数：{}， 缓存结果：{}",
                    resultStr, commandDto.getVin(), commandStr,
                    controlCommandStr, controlContent, commandDto,
                    commandDtoCache.getResult());
            return;
        }

        //达到最大补发次数
        if(commandDto.getSendingTimes() >= Constant.GENERAL_DELAY_TIMES){
            logger.info("[补发] 取消 原因：[已达到最大补发次数]  vin：{}, command：{}, " +
                            "controlCommand：{}, controlContent：{}  参数：{}， 缓存结果：{}",
                    commandDto.getVin(), commandStr, controlCommandStr,
                    controlContent, commandDto, commandDtoCache.getResult());

            //置为失败：更新数据库、缓存
            commandDtoCache.setResult(ResResultEnum.ERROR.getFlag());

            sendCache.updateResResult(commandDto, commandDtoCache);

            udpateResult(commandDtoCache.getVin(),commandDtoCache.getCommandNo(),
                         OperatorResultEnum.FAIL.getFlag(),ResResultEnum.ERROR.getMsg());
            return;
        }

        retrySend(commandDto);
    }

    /**
     * 补发升级命令
     * @param commandDto
     */
    public void retrySend(CommandDto commandDto){
        DataEncoder dataEncoder = DataEncoderFactory.getDataEncoder(commandDto.getCommand());
        if(dataEncoder == null){
            logger.error("[补发]，普通指令处理 失败，未定义命令协议, 命令协议：{}, 参数：{}",
                    commandDto.getCommand(), commandDto);
            return;
        }
        byte[] data = dataEncoder.encode(commandDto);

        ProtocolEncoder protocolEncoder = new ProtocolEncoder(commandDto.getCommand(),
                ByteArrayUtil.strToAscii(commandDto.getVin()), data);
        //整包数据
        byte[] allData = protocolEncoder.endcode();
        sendHandle.retrySend(commandDto, allData);
    }

    /**
     * 更新数据库
     * @param vin
     * @param responseNo
     * @param result
     * @param resultMemo
     */
    public void udpateResult(String vin, Long responseNo, Integer result, String resultMemo){
        VehicleCommand vehicleCommand = new VehicleCommand();
        vehicleCommand.setVin(vin);
        vehicleCommand.setResponseNo(responseNo);
        vehicleCommand.setResult(result);
        vehicleCommand.setResultMemo(resultMemo);
        logger.info("[补发] 取消 原因：[已达到最大补发次数] 更新数据：{}", vehicleCommand);
        vehicleCommandService.updateResult(vehicleCommand);
    }
}
